{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Selection Detail Example\n",
    "========================\n",
    "This example shows a selection that links two views of data: the left panel\n",
    "contains one point per object, and the right panel contains one line per\n",
    "object. Clicking on either the points or lines will select the corresponding\n",
    "objects in both views of the data.\n",
    "\n",
    "The challenge lies in expressing such hierarchical data in a way that Altair\n",
    "can handle. We do this by merging the data into a \"long form\" dataframe, and\n",
    "aggregating identical metadata for the final plot.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# category: interactive\n",
    "\n",
    "import altair as alt\n",
    "alt.data_transformers.enable('json')\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "\n",
    "np.random.seed(0)\n",
    "\n",
    "n_objects = 20\n",
    "n_times = 50\n",
    "\n",
    "# Create one (x, y) pair of metadata per object\n",
    "locations = pd.DataFrame({\n",
    "    'id': range(n_objects),\n",
    "    'x': np.random.randn(n_objects),\n",
    "    'y': np.random.randn(n_objects)\n",
    "})\n",
    "\n",
    "# Create a 50-element time-series for each object\n",
    "timeseries = pd.DataFrame(np.random.randn(n_times, n_objects).cumsum(0),\n",
    "                          columns=locations['id'],\n",
    "                          index=pd.RangeIndex(0, n_times, name='time'))\n",
    "\n",
    "# Melt the wide-form timeseries into a long-form view\n",
    "timeseries = timeseries.reset_index().melt('time')\n",
    "\n",
    "# Merge the (x, y) metadata into the long-form view\n",
    "data = pd.merge(timeseries, locations, on='id')\n",
    "\n",
    "# Data is prepared, now make a chart\n",
    "\n",
    "selector = alt.selection_single(empty='all', fields=['id'])\n",
    "\n",
    "points = alt.Chart(data).mark_point(filled=True, size=200).encode(\n",
    "    x='mean(x)',\n",
    "    y='mean(y)',\n",
    "    color=alt.condition(selector, 'id:O', alt.value('lightgray'), legend=None),\n",
    ").properties(\n",
    "    selection=selector,\n",
    "    width=250, height=250\n",
    ").interactive()\n",
    "\n",
    "timeseries = alt.Chart(data).mark_line().encode(\n",
    "    x='time',\n",
    "    y=alt.Y('value', scale=alt.Scale(domain=(-15, 15))),\n",
    "    color=alt.Color('id:O', legend=None)\n",
    ").transform_filter(\n",
    "    selector\n",
    ").properties(\n",
    "    selection=selector,\n",
    "    width=250, height=250\n",
    ")\n",
    "\n",
    "points | timeseries\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "env": {},
   "interrupt_mode": "signal",
   "language": "python",
   "metadata": {},
   "name": "python3"
  },
  "language": "python"
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
